#pragma once

#include"common.hpp"
#include <jsoncpp/json/json.h>

const std::string Calsep = "\r\n";

class Request{
    public:
    Request(int x,int y,char oper)
    :_x(x),
    _y(y),
    _oper(oper)
    {}

    Request(){}

    int GetX(){return _x;}
    int GetY(){return _y;}
    char GetOper(){return _oper;}

    std::string Serialize()
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter writer;
        std::string s = writer.write(root);
        return s;
    }

    bool Deserialize(std::string& in)
    {
        Json::Value root;
        Json::Reader reader;
        bool n = reader.parse(in,root);
        if(n){
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return n;
    }

    ~Request(){}

    private:
    int _x;
    int _y;
    char _oper;
};


class Respond{
    public:
    Respond(){}
    Respond(int result,std::string code):_result(result),_code(code){}
    Respond(const Respond& res)
    :_result(res._result),
    _code(res._code)
    {}

    std::string Serialize()
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::FastWriter writer;
        std::string s = writer.write(root);
        return s;
    }

    bool Deserialize(std::string& in)
    {
        Json::Value root;
        Json::Reader reader;
        bool n = reader.parse(in,root);
        if(n){
            _result = root["result"].asInt();
            _code = root["code"].asString();
        }
        return n;
    }

    void CoutResult()
    {
        std::cout<<"result: "<<_result<<" code:"<<_code<<std::endl;
    }

        int Getresult(){
        return _result;
    }

    std::string Getcode(){
        return _code;
    }

    private:
    int _result;
    std::string _code;

};

using protcfun = std::function<Respond(Request& req)>;

class protocol
{
   
public:
    protocol(protcfun pfun):_fun(pfun)
    {}
    protocol(){}

    std::string Encode(std::string json_str){
        int len = json_str.size();
        std::string tmp = std::to_string(len) + Calsep + json_str + Calsep;
        return tmp; 
    }

    bool Decode(std::string& json_str,std::string* in){

       // LOG(level::DEBUG)<<"In Decode";
        std::size_t pos = json_str.find(Calsep);
        if(pos == std::string::npos)
        {
            //LOG(level::DEBUG)<<"NO FIND SEP";
            return false;
        }
        std::string len_jsonstr = json_str.substr(0,pos);
        int len = std::stoi(len_jsonstr);
        int wholesize = len_jsonstr.size() + len + 2*Calsep.size();
        if(wholesize >= json_str.size())
        {
            *in = json_str.substr(pos + Calsep.size(),wholesize);
            json_str.erase(0,wholesize);
            return true; 
        }
        //LOG(level::DEBUG)<<"Decode end";
        return false;
    }

    //50\r\n{}\r\n
    //50\r\n{}\r\n
    void GetRequest(std::shared_ptr<TcpSocket> tcso)
    {
        //LOG(level::DEBUG)<<"In Getreqeust";
        std::string buff;
        while(1)
        {
            int rsz = tcso->Recv(&buff);
            if(rsz > 0){
                //LOG(level::DEBUG)<<"Recv success "<<buff;
                std::string message;
                int n = Decode(buff,&message);
                if(!n){
                    std::cout<<n<<std::endl;
                    continue;
                }
                //LOG(level::DEBUG)<<"DEcode success "<<message;

                Request rqs;
                rqs.Deserialize(message);
                //std::cout<<rqs.GetX()<<" "<<rqs.GetOper()<<std::endl;
                Respond res(_fun(rqs));

                std::string s = Encode(res.Serialize());
                //LOG(level::DEBUG)<<s;
                tcso->Send(s);
            }
            else if(rsz == 0){
                LOG(level::INFO)<<"进程退出....";
                break;
            }
            else{
                LOG(level::ERROR)<<"读取异常....";
                break;
            }
        }
    }

    ~protocol(){}

private:
    protcfun _fun;
};

